package com.flaskpy.web.eternity.log.aspect;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.flaskpy.web.eternity.log.entity.LogArgs;
import com.flaskpy.web.eternity.log.service.IAopLogService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

@Aspect
@Slf4j
public class LogAscept  implements ApplicationContextAware {

    private  ApplicationContext applicationContext;

    /**
     * 配置切入点
     */
    @Pointcut("@annotation(com.flaskpy.web.eternity.log.aspect.AopLog)")
    public void logPointcut() {


    }
    @Before("logPointcut()")
    public void beforeAdvice(){

    }


    @After("logPointcut()")
    public void afterAdvice(){

    }

    @AfterReturning(pointcut = "logPointcut()", returning="retVal")
    public void afterReturningAdvice(Object retVal){


    }


    private static ThreadLocal<Long> startTimeLocal=new ThreadLocal<>();
    @Around("logPointcut()")
    public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {



        startTimeLocal.set( System.currentTimeMillis());
        Object retVal = pjp.proceed();
        long endMillis = System.currentTimeMillis();

        saveLog(pjp,retVal,endMillis,null);



        return retVal;
    }
    @SneakyThrows
    private void saveLog(JoinPoint pjp,Object retVal, Long endMillis,IllegalArgumentException ex){

        Long startMillis = startTimeLocal.get();
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        AopLog aopLog = method.getAnnotation(AopLog.class);
        Class<? extends IAopLogService> serverType = aopLog.serverType(); //获取指定的service类型
        IAopLogService currentLogoutput = this.applicationContext.getBean(serverType);
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request =((ServletRequestAttributes)requestAttributes).getRequest();
        LogArgs loginfo = LogArgs.builder().request(request).result(retVal).joinPoint(pjp).
                elapsed( endMillis-startMillis).build();
        loginfo.setStartTime( LocalDateTimeUtil.of(startMillis));
        currentLogoutput.save(loginfo);

    }
    @AfterThrowing(pointcut = "logPointcut()", throwing = "ex")
    public void AfterThrowingAdvice(JoinPoint joinPoint, IllegalArgumentException ex){

        saveLog(joinPoint,null,System.currentTimeMillis(),ex);

    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }
}
